<!DOCTYPE html>
<html lang="zh-cn">
  <head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta name="author" content="Zhou Wei <zromyk@163.com>">
  <title>gdb debug</title>
  <link rel="shortcut icon" href="/favicon.ico">
  <link rel="stylesheet" href="/style/html/pure.css">
  <link rel="stylesheet" href="/style/html/main.css">
  <link rel="stylesheet" href="https://cdn.staticfile.org/font-awesome/4.7.0/css/font-awesome.css">
  <!-- <link rel="stylesheet" href="https://apps.bdimg.com/libs/highlight.js/9.1.0/styles/default.min.css"> -->
<link rel="stylesheet" href="/style/article/highlight/default.min.css">
<link rel="stylesheet" href="/style/article/pell-1.0.6/dist/pell.css">

</head>
<body>
  <div id="menu-background"></div>
  <div id="menu">
    <div class="pure-menu pure-menu-horizontal">
  <ul class="pure-menu-list block-middle">
    <li class="pure-menu-item">
  <a class="pure-menu-heading" href="/index.html">ZROMYK</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" href="/index.html">主页</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" href="/public/archive/index.html">归档</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" href="/public/download/index.html">下载</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" href="/public/feedback/index.html">反馈</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" href="/public/about/index.html">关于我</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" href="https://github.com/zromyk"><i class="fa fa-github" style="font-size:32px"></i></a>
</li>

  </ul>
</div>

  </div>
  <div id="layout">
    <div class="content">
      <div id="nav">
    <div id="navigation" class="navigation">
  <ul class="pure-menu-list">
    <li class="pure-menu-item">
  <a class="pure-menu-link nav2" onclick="animateByNav()" href="#_1">一、预先准备测试程序</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav3" onclick="animateByNav()" href="#11">1.1 编译</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav3" onclick="animateByNav()" href="#12-readelf">1.2 readelf查看段信息</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav2" onclick="animateByNav()" href="#gdb-tui">二、<span style="overflow-x: auto; max-width:100%; display:inline;"><code>gdb -tui</code></span> 图像化界面</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav2" onclick="animateByNav()" href="#gdb-debug">三、<span style="overflow-x: auto; max-width:100%; display:inline;"><code>gdb debug</code></span></a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav3" onclick="animateByNav()" href="#31-file">3.1 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>file</code></span> 加载程序</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav3" onclick="animateByNav()" href="#32-list">3.2 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>list</code></span> 显示源文件</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav3" onclick="animateByNav()" href="#33-run">3.3 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>run</code></span> 运行程序</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav3" onclick="animateByNav()" href="#34-break">3.4 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>break</code></span> 设置断点</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav5" onclick="animateByNav()" href="#_2">设置断点</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav5" onclick="animateByNav()" href="#_3">条件断点</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav5" onclick="animateByNav()" href="#_4">查看断点</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav5" onclick="animateByNav()" href="#_5">删除断点</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav5" onclick="animateByNav()" href="#_6">禁用 / 开启断点</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav5" onclick="animateByNav()" href="#ignore">ignore</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav3" onclick="animateByNav()" href="#35">3.5 显示堆栈</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav3" onclick="animateByNav()" href="#36">3.6 变量操作</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav3" onclick="animateByNav()" href="#37">3.7 调试函数</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav5" onclick="animateByNav()" href="#disassemble"><span style="overflow-x: auto; max-width:100%; display:inline;"><code>disassemble</code></span></a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav5" onclick="animateByNav()" href="#call"><span style="overflow-x: auto; max-width:100%; display:inline;"><code>call</code></span></a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav3" onclick="animateByNav()" href="#38">3.8 退出调试</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav2" onclick="animateByNav()" href="#_7">四、多进程调试</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav3" onclick="animateByNav()" href="#41">4.1 配置</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav3" onclick="animateByNav()" href="#42">4.2 查看进程</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav2" onclick="animateByNav()" href="#_8">五、多线程调试</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav3" onclick="animateByNav()" href="#51">5.1 查看线程</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav3" onclick="animateByNav()" href="#52">5.2 查看线程堆栈</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav3" onclick="animateByNav()" href="#53">5.3 切换线程</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav3" onclick="animateByNav()" href="#54">5.4 阻塞线程</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav2" onclick="animateByNav()" href="#_9">附录</a>
</li>

  </ul>
</div>

</div>
<div id="content-articles">
  <h1 id="gdb debug" class="content-subhead">gdb debug</h1>
  <p>
    <span>2021-04-10</span>
    <span><span class="post-category post-category-other">C/C++</span></span>
    <button id="button-markdownEditor" class="pure-button" onclick="markdownEditor()">启用编辑</button>
    <button id="button-save" class="pure-button" onclick="save()">保存</button>
  </p>
  <div id="content-articles-markdownEditor" style="display: none;">
    <h1>编辑 power by pell</h1>
    <div id="editor" class="pell"></div>
    <div style="margin-top:20px;">
        <h3>Text output:</h3>
        <div id="text-output"></div>
    </div>
    <div style="margin-top:20px;">
        <h3>HTML output:</h3>
        <pre id="html-output"></pre>
    </div>
  </div>
  <div id="content-articles-markdown">
    <h2 id="_1">一、预先准备测试程序</h2>
<h3 id="11">1.1 编译</h3>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-c++">#include &lt;stdio.h&gt;

int add(int x, int y) {
    return x + y;
}

int main() {
    int a = 1;
    int b = 2;
    int c = 0;

    printf(&quot;a = %d\n&quot;, a);
    printf(&quot;b = %d\n&quot;, b);

    c = add(a, b);
    printf(&quot;%d + %d = %d\n&quot;, a, b, c);

    return 0;
}
</code></span></code></pre>
<p>使用 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>gcc</code></span> 编译源文件</p>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-shell">gcc -g hello.c -o hello
</code></span></code></pre>
<h3 id="12-readelf">1.2 readelf查看段信息</h3>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-shell">readelf -S hello | grep debug
  [27] .debug_aranges    PROGBITS         0000000000000000  0000108e
  [28] .debug_info       PROGBITS         0000000000000000  000010be
  [29] .debug_abbrev     PROGBITS         0000000000000000  000011ae
  [30] .debug_line       PROGBITS         0000000000000000  0000122a
  [31] .debug_str        PROGBITS         0000000000000000  00001273
</code></span></code></pre>
<h2 id="gdb-tui">二、<span style="overflow-x: auto; max-width:100%; display:inline;"><code>gdb -tui</code></span> 图像化界面</h2>
<p>输入以下命令可以打开 gdb 自带的 tui 图像调试界面</p>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-shell">gdb -tui hello
</code></span></code></pre>
<p>说明：使用 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>-tui</code></span> 参数可以将调试窗口分为两部分：上面是源码，下面是调试信息，使用 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>Ctrl+n/Ctrl+p</code></span> 或者方向键进行翻页。</p>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-c">   ┌──hello.c──────────────────────────────────────────────────────────┐
   │1       #include &lt;stdio.h&gt;                                         │
   │2                                                                  │
   │3       int add(int x, int y) {                                    │
   │4           return x + y;                                          │
   │5       }                                                          │
   │6                                                                  │
   │7       int main() {                                               │
   │8           int a = 1;                                             │
   │9           int b = 2;                                             │
   │10          int c = 0;                                             │
   │11                                                                 │
   │12          printf(&quot;a = %d\n&quot;, a);                                 │
   │13          printf(&quot;b = %d\n&quot;, b);                                 │
   │14                                                                 │
   │15          c = add(a, b);                                         │
   │16          printf(&quot;%d + %d = %d\n&quot;, a, b, c);                     │
   │17                                                                 │
   │18          return 0;                                              │
   │19      }                                                          │
   │20                                                                 │
   │21                                                                 │
   │22                                                                 │
   │23                                                                 │
   │24                                                                 │
   │25                                                                 │
   │26                                                                 │
   └───────────────────────────────────────────────────────────────────┘
exec No process In:                                   Line: ??   PC: ?? 
Reading symbols from /home/zromyk/Desktop/hello/hello...done.
(gdb) 

</code></span></code></pre>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code>(gdb) help layout
Layout names are:
   src   : Displays source and command windows.
   asm   : Displays disassembly and command windows.
   split : Displays source, disassembly and command windows.
   regs  : Displays register window. If existing layout
           is source/command or assembly/command, the 
           register window is displayed. If the
           source/assembly/command (split) is displayed, 
           the register window is displayed with 
           the window that has current logical focus.
</code></span></code></pre>
<p>可以通过以下命令在各个 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>layout</code></span> 之间切换：</p>
<div class="pure-table-scrollable"><table class="pure-table pure-table-horizontal">
<thead>
<tr>
<th>Command</th>
<th>Describe</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>ayout src</strong></td>
<td>Standard layout—source on top, command window on the bottom</td>
</tr>
<tr>
<td><strong>layout asm</strong></td>
<td>Just like the &ldquo;src&rdquo; layout, except it&rsquo;s an assembly window on top</td>
</tr>
<tr>
<td><strong>layout split</strong></td>
<td>Three windows: source on top, assembly in the middle, and command at the bottom</td>
</tr>
<tr>
<td><strong>layout reg</strong></td>
<td>Opens the register window on top of either source or assembly, whichever was opened last</td>
</tr>
</tbody>
</table></div>
<h2 id="gdb-debug">三、<span style="overflow-x: auto; max-width:100%; display:inline;"><code>gdb debug</code></span></h2>
<p><a href="https://my.oschina.net/u/4802134/blog/4716378?hmsr=kaifa_aladdin">[详解gdb的使用技巧](https://my.oschina.net/u/4802134/blog/4716378)</a></p>
<h3 id="31-file">3.1 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>file</code></span> 加载程序</h3>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-shell">(gdb) file [可执行文件]
# Reading symbols from /.../filename...done.
</code></span></code></pre>
<blockquote class="content-quote">
<p>若程序未提前编译，可以在 gdb 中 通过 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>shell</code></span> 命令打开 shell 终端，然后使用 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>exit</code></span> 退出。</p>
<p><span style="overflow-x: auto; max-width:100%; display:inline;"><code>shell
(gdb) shell
✔︎ zromyk@centos hello $ gcc -g hello.c -o hello
✔︎ zromyk@centos hello $ exit
(gdb)</code></span></p>
</blockquote>
<h3 id="32-list">3.2 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>list</code></span> 显示源文件</h3>
<p>使用 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>list</code></span> 或 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>l</code></span> 显示源文件的前 10 行，之后继续输入 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>list</code></span> 或 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>l</code></span> 或 回车，可以继续显示下面的内容：</p>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-shell">(gdb) list
1   #include &lt;stdio.h&gt;
2   
3   int add(int x, int y) {
4       return x + y;
5   }
6   
7   int main() {
8       int a = 1;
9       int b = 2;
10      int c = 0;
(gdb) 
</code></span></code></pre>
<p>如果要从头开始显示，或者从指定行开始显示可以使用</p>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-shell">(gdb) list 1    # or other number
</code></span></code></pre>
<h3 id="33-run">3.3 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>run</code></span> 运行程序</h3>
<p><strong>重新运行：</strong><span style="overflow-x: auto; max-width:100%; display:inline;"><code>run/r</code></span></p>
<p><strong>继续执行：</strong><span style="overflow-x: auto; max-width:100%; display:inline;"><code>continue/c</code></span></p>
<p><strong>单步执行：</strong><span style="overflow-x: auto; max-width:100%; display:inline;"><code>next/n N</code></span> (执行 N 次 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>next</code></span>)</p>
<p><strong>单步进入：</strong><span style="overflow-x: auto; max-width:100%; display:inline;"><code>step/s</code></span> (遇到函数进入函数内部，退出函数时使用 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>finish</code></span> )</p>
<p><strong>结束函数：</strong><span style="overflow-x: auto; max-width:100%; display:inline;"><code>finish/f</code></span></p>
<p><strong>强制返回：</strong><span style="overflow-x: auto; max-width:100%; display:inline;"><code>return</code></span> (忽略当前未执行的部分，强制返回)</p>
<h3 id="34-break">3.4 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>break</code></span> 设置断点</h3>
<h5 id="_2">设置断点</h5>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-shell">(gdb) b 函数名          # 函数打断点
(gdb) b 源文件名:行号    # 某一行打断点
</code></span></code></pre>
<h5 id="_3">条件断点</h5>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-shell">(gdb) break 断点 if 条件
(gdb) continue 断点编号 (执行一次表示设定，再次执行表示取消)
(gdb) continue 断点编号 条件
</code></span></code></pre>
<p>注：条件断点非常有用，实际调试中往往需要调试特定场景下函数调用关系，此时就需要设置断点触发的条件。</p>
<h5 id="_4">查看断点</h5>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code>(gdb) info breakpoint
(gdb) info break
(gdb) info b
</code></span></code></pre>
<h5 id="_5">删除断点</h5>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-shell">(gdb) delete 断点号
(gdb) delete (删除所有断点)
</code></span></code></pre>
<h5 id="_6">禁用 / 开启断点</h5>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-shell">(gdb) disable
(gdb) enable breakpoint
</code></span></code></pre>
<h5 id="ignore">ignore</h5>
<p>断点条件的一个特殊用法是，程序只有在到达断点一定次数之后才会停止，此时可以使用指令：</p>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-shell">(gdb) ignore 断点编号 次数
(gdb) ignore 2 10 # 触发断点 10 次后才会停止，每次触发断点 count 自动减 1
</code></span></code></pre>
<p>说明：打完断点是不是执行 continue 就可以等待着运行到断点了呢？不一定，有时候断点处代码的执行需要外部触发，比如 web 发送特定消息后才可以触发执行，如果一直等待没有消息出发永远执行不到断点处，此时就需要结合自己的业务逻辑，手动设置出发条件。</p>
<h3 id="35">3.5 显示堆栈</h3>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-shell">(gbd) backstrace/bt
</code></span></code></pre>
<p>有时候跳转的次数太多，不知道具体调用的层级关系了，可以使用bt查看堆栈，该命令会产生一张列表，包含着运行过程和相关的参数。</p>
<h3 id="36">3.6 变量操作</h3>
<p><strong>设置变量：</strong><span style="overflow-x: auto; max-width:100%; display:inline;"><code>set 变量 = 表达式</code></span></p>
<p>在调试的时候，有时候需要设置一些假数据查看对应输出，比如根据布尔值查看流程执行情况，此时就需要在执行到指定位置时手动设置一下数据的取值。</p>
<p><strong>监控变量：</strong></p>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-shell">(gdb) watch varName  # 数值改变时暂停运行)
(gdb) awatch &lt;表达式&gt; # 被访问或改变时暂停运行)
(gdb) rwatch &lt;表达式&gt; # 被访问时暂停运行)
</code></span></code></pre>
<p>有时候我们需要观察一个变量的变化过程，比如一个全局变量如何初始化，如何调用的，这就需要使用 watch 监控变量。</p>
<p><strong>变量类型：</strong></p>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-shell">(gdb) ptype var     # 变量类型
(gdb) whatis var    # 显示一个变量 var 的类型
</code></span></code></pre>
<p><strong>打印变量：</strong><span style="overflow-x: auto; max-width:100%; display:inline;"><code>print/p 变量</code></span></p>
<p><strong>打印字符/表达式：</strong><span style="overflow-x: auto; max-width:100%; display:inline;"><code>print/p “%s”, 字符/表达式</code></span></p>
<p><strong>格式化输出：</strong><span style="overflow-x: auto; max-width:100%; display:inline;"><code>print/p/格式控制符 打印内容</code></span></p>
<h3 id="37">3.7 调试函数</h3>
<h5 id="disassemble"><span style="overflow-x: auto; max-width:100%; display:inline;"><code>disassemble</code></span></h5>
<p>可以使用反汇编的指令 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>disassemble</code></span> 去探究究竟在函数中发生了哪些操作，具体如下：</p>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-shell">disassemble                     # 反汇编当前整个函数
disassemble 程序计数器           # 反汇编计数器所在函数的整个函数
disassemble 开始地址 结束地址   # 反汇编从开始地址到结束地址的部分
</code></span></code></pre>
<h5 id="call"><span style="overflow-x: auto; max-width:100%; display:inline;"><code>call</code></span></h5>
<p>强制调用函数：call 表达式</p>
<h3 id="38">3.8 退出调试</h3>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code>(gdb) quit/q
</code></span></code></pre>
<p>在执行到断点后，采用 quit/q 指令退出。</p>
<h2 id="_7">四、多进程调试</h2>
<h3 id="41">4.1 配置</h3>
<p><strong>detach-on-fork</strong>：该属性决定了 gdb 是同时调试父子进程，还是在 fork 了子进程之后，将子进程分离出去。</p>
<ul>
<li>on：子进程（或者父进程，取决于gdb在初始时，要调试的进程，也就是 follow-fork-mode 的值）</li>
<li>off：同时调试父子进程，一个进程处于被调试的状态，而另一个则被 gdb 挂起</li>
</ul>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-shell">(gdb) set detach-on-fork on/off
</code></span></code></pre>
<p><strong>follow-fork-mode</strong>：该属性决定了 gdb 在进程调用 fork 之后的行为。</p>
<ul>
<li>set follow-fork-mode parent：默认情况下，在调用 fork 之后，gdb 选择跟随（也就是调试）父进程，而子进程则在处于运行的状态（此时父进程处于阻塞的状态）。</li>
<li>set follow-fork-mode child：fork 之后 gdb 选择调试子进程，而父进程处于运行的状态。</li>
</ul>
<h3 id="42">4.2 查看进程</h3>
<p>查看当前调试的进程：</p>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-shell">(gdb) info inferiors
</code></span></code></pre>
<h2 id="_8">五、多线程调试</h2>
<h3 id="51">5.1 查看线程</h3>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-shell">(gdb) info threads
</code></span></code></pre>
<p>注：输出信息前面有“*”表示调试的当前线程（一般 thread 切换线程后查看）。</p>
<p>有的程序会在运行过程中主线程创建多个子线程，所以前后执行 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>info threads</code></span> 显示的线程数是会动态变化的。</p>
<h3 id="52">5.2 查看线程堆栈</h3>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-shell">(gdb) thread apply all bt                   # 查看所有线程堆栈
(gdb) thread apply thread1 thread2... bt    # 查看指定线程堆栈
</code></span></code></pre>
<h3 id="53">5.3 切换线程</h3>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code>(gdb) thread N
</code></span></code></pre>
<p>注：通过打印 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>counter</code></span>，可以看到多个线程都是在运行的，如果想要让其他线程处于停止状态，只有当前调试的线程执行，可以采用 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>set scheduler-locking on</code></span>。</p>
<h3 id="54">5.4 阻塞线程</h3>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-shell">(gdb) set scheduler-locking # 阻塞其他线程，仅调试当前线程工作
(gdb) thread apply N command # 运行指定线程并允许其他线程并行执行
</code></span></code></pre>
<h2 id="_9">附录</h2>
<p>https://blog.csdn.net/awm_kar98/article/details/82840811</p>
<div class="pure-table-scrollable"><table class="pure-table pure-table-horizontal">
<thead>
<tr>
<th>(gdb)</th>
<th>Command</th>
<th>描述</th>
<th>简写</th>
</tr>
</thead>
<tbody>
<tr>
<td>(gdb)</td>
<td>help</td>
<td>查看命令帮助，具体命令查询在gdb中输入 help + 命令</td>
<td>h</td>
</tr>
<tr>
<td>(gdb)</td>
<td>run</td>
<td>重新开始运行文件（run text 加载文本文件，run bin 加载二进制文件）</td>
<td>r</td>
</tr>
<tr>
<td>(gdb)</td>
<td>start</td>
<td>单步执行，运行程序，停在第一执行语句</td>
<td></td>
</tr>
<tr>
<td>(gdb)</td>
<td>list</td>
<td>查看原代码（list n : 从第 n 行开始查看代码 list + 函数名 : 查看具体函数）</td>
<td>l</td>
</tr>
<tr>
<td>(gdb)</td>
<td>set</td>
<td>设置变量的值</td>
<td></td>
</tr>
<tr>
<td>(gdb)</td>
<td>next</td>
<td>单步调试（逐过程，函数直接执行）</td>
<td>n</td>
</tr>
<tr>
<td>(gdb)</td>
<td>step</td>
<td>单步调试（逐语句，跳入自定义函数内部执行）</td>
<td>s</td>
</tr>
<tr>
<td>(gdb)</td>
<td>backtrace</td>
<td>查看函数的调用的栈帧和层级关系</td>
<td>bt</td>
</tr>
<tr>
<td>(gdb)</td>
<td>frame</td>
<td>切换函数的栈帧</td>
<td>f</td>
</tr>
<tr>
<td>(gdb)</td>
<td>info</td>
<td>查看函数内部局部变量的数值</td>
<td>i</td>
</tr>
<tr>
<td>(gdb)</td>
<td>finish</td>
<td>结束当前函数，返回到函数调用点</td>
<td></td>
</tr>
<tr>
<td>(gdb)</td>
<td>continue</td>
<td>继续运行</td>
<td>c</td>
</tr>
<tr>
<td>(gdb)</td>
<td>print</td>
<td>打印值及地址</td>
<td>p</td>
</tr>
<tr>
<td>(gdb)</td>
<td>quit</td>
<td>退出 gdb</td>
<td>q</td>
</tr>
<tr>
<td>(gdb)</td>
<td>break num</td>
<td>在第 num 行设置断点</td>
<td>b</td>
</tr>
<tr>
<td>(gdb)</td>
<td>info breakpoints</td>
<td>查看当前设置的所有断点</td>
<td></td>
</tr>
<tr>
<td>(gdb)</td>
<td>delete breakpoints num</td>
<td>删除第 num 个断点</td>
<td>d</td>
</tr>
<tr>
<td>(gdb)</td>
<td>display</td>
<td>追踪查看具体变量值</td>
<td></td>
</tr>
<tr>
<td>(gdb)</td>
<td>undisplay</td>
<td>取消追踪观察变量</td>
<td></td>
</tr>
<tr>
<td>(gdb)</td>
<td>watch</td>
<td>被设置观察点的变量发生修改时，打印显示</td>
<td></td>
</tr>
<tr>
<td>(gdb)</td>
<td>i watch</td>
<td>显示观察点</td>
<td></td>
</tr>
<tr>
<td>(gdb)</td>
<td>enable breakpoints</td>
<td>启用断点</td>
<td></td>
</tr>
<tr>
<td>(gdb)</td>
<td>disable breakpoints</td>
<td>禁用断点</td>
<td></td>
</tr>
<tr>
<td>(gdb)</td>
<td>x</td>
<td>查看内存 x/20xw 显示20个单元，16进制，4字节每单元</td>
<td></td>
</tr>
<tr>
<td>(gdb)</td>
<td>run argv[1] argv[2]</td>
<td>调试时命令行传</td>
<td></td>
</tr>
</tbody>
</table></div>
  </div>
</div>
 
    </div>
  </div>
  <div id="footer-background">
    <div id="footer">
      <div class="legal pure-g">
  <div class="pure-u-1 u-sm-1-2">
    <p class="legal-license"><a href="https://beian.miit.gov.cn/#/Integrated/index">浙ICP备2020038748号</a></p>
  </div>
  <div class="pure-u-1 u-sm-1-2">
    <p class="legal-links"><a href="https://github.com/zromyk">GitHub</a></p>
    <p class="legal-copyright">Copyright © 2021 Wei Zhou. 保留所有权利。</p>
  </div>
</div>
    </div>
  </div>
  <!-- <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script> -->
  <script src="/style/html/jquery.min.js"></script>
  <script src='/style/article/latex/latest.js?config=TeX-MML-AM_CHTML'></script>
<!-- <script src="https://cdn.geogebra.org/apps/deployggb.js"></script> -->
<script src="/style/article/deployggb.js"></script>
<!-- <script src="https://apps.bdimg.com/libs/highlight.js/9.1.0/highlight.min.js"></script> -->
<script type="text/javascript">
  // 脚本：navigation 随鼠标移动自动变换宽度
  var element = document.getElementById("navigation"); // 获取要操作的元素
  var elementWidth = parseInt(getComputedStyle(element).width);
  var elementLeft = 0;
  var elementRight = 0;
  element.addEventListener('mouseenter', function (event) { // 添加鼠标按下事件的监听器
    elementLeft = element.getBoundingClientRect().left - 10;
    elementRight = element.getBoundingClientRect().left + elementWidth * 3;
    window.addEventListener('mousemove', resize); // 添加全局的鼠标移动事件的监听器
  });

  function resize(event) {
    var minWidth = elementWidth;
    var maxWidth = elementWidth * 2.5;
    // console.log(elementLeft, event.clientX, elementRight, event.clientX - elementLeft + elementWidth / 2);
    if (elementLeft <= event.clientX && event.clientX <= elementRight) {
      var width = event.clientX - elementLeft + elementWidth / 2;
      width = Math.min(width, maxWidth);
      width = Math.max(width, minWidth);
      element.style.width = width + 'px'; // 设置新的宽度样式属性
    }
    else {
      element.style.width = elementWidth + 'px'; // 设置新的宽度样式属性
      stopResize();
    }
  }

  function stopResize() {
    element.style.width = elementWidth + 'px'; // 设置新的宽度样式属性
    // console.log("stopResize", elementLeft, event.clientX, elementRight, event.clientX - elementLeft + elementWidth / 2);
    window.removeEventListener('mousemove', resize); // 移除鼠标移动事件的监听器
  }
</script>
<script src="/style/article/highlight/highlight.min.js"></script>
<script type="text/javascript">
  // 脚本：code语法高亮
  hljs.initHighlightingOnLoad();
</script>
<script>
  function animateByNav() {
    $("html").animate({
        scrollTop: ($(event.target.hash).offset().top - 52)
    }, 300);
  };
</script>
<script src="/style/article/pell-1.0.6/dist/pell.js"></script>
<script>
  // 脚本：自由编辑页面
  var editor = window.pell.init({
    element: document.getElementById('editor'),
    defaultParagraphSeparator: 'p',
    onChange: function(html) {
        document.getElementById('text-output').innerHTML = html
        document.getElementById('html-output').textContent = html
    }
  });

  function markdownEditor() {
    var articles = document.getElementById('content-articles-markdown');
    if (articles.getAttribute("contenteditable") == "true") {
        articles.setAttribute("contenteditable", "false");
        document.getElementById("content-articles-markdownEditor").style.display = "none"; //隐藏
        document.getElementById("button-markdownEditor").innerHTML = "启用编辑";
    } else {
        articles.setAttribute("contenteditable", "true");
        document.getElementById("content-articles-markdownEditor").style.display = ""; //显示
        document.getElementById("button-markdownEditor").innerHTML = "关闭编辑";
    }
  };

  function save() {
      window.alert("保存成功");
  };
</script>

</body>
</html>
